[PATCH 2/2] output: use tx iterator for finding alert http xff
authorPhilippe Antoine <pantoine@oisf.net>
Tue, 9 Dec 2025 08:38:31 +0000 (09:38 +0100)
committerAndreas Dolp <dev@andreas-dolp.de>
Sun, 22 Feb 2026 12:28:52 +0000 (13:28 +0100)
Ticket: 8156

Allows better performance.

(cherry picked from commit ab2e128176744ead5130707bb53fa59038e19634)

Origin: upstream, https://github.com/OISF/suricata/commit/7e704a3f50690b5f5d5cc573147ef41449fe37ac.patch
Bug: https://redmine.openinfosecfoundation.org/issues/8156
Subject: Upstream fix for CVE-2026-22261 part 2

Gbp-Pq: Name CVE-2026-22261_2.patch

src/app-layer-htp-xff.c

index 6eae5b1b3848c297cfc8d19b7218572d008b7c0c..2e5c25cdb3a848cd3486dff32455fae0b3f868cb 100644 (file)
@@ -107,38 +107,12 @@ static int ParseXFFString(char *input, char *output, int output_size)
     return 0;
 }
 
-/**
- * \brief Function to return XFF IP if any in the selected transaction. The
- * caller needs to lock the flow.
- * \retval 1 if the IP has been found and returned in dstbuf
- * \retval 0 if the IP has not being found or error
- */
-int HttpXFFGetIPFromTx(const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg,
-        char *dstbuf, int dstbuflen)
+static int HttpXFFGetIPFromTxAux(
+        const Flow *f, htp_tx_t *tx, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen)
 {
     uint8_t xff_chain[XFF_CHAIN_MAXLEN];
-    HtpState *htp_state = NULL;
-    htp_tx_t *tx = NULL;
-    uint64_t total_txs = 0;
     uint8_t *p_xff = NULL;
 
-    htp_state = (HtpState *)FlowGetAppState(f);
-
-    if (htp_state == NULL) {
-        SCLogDebug("no http state, XFF IP cannot be retrieved");
-        return 0;
-    }
-
-    total_txs = AppLayerParserGetTxCnt(f, htp_state);
-    if (tx_id >= total_txs)
-        return 0;
-
-    tx = AppLayerParserGetTx(f->proto, ALPROTO_HTTP1, htp_state, tx_id);
-    if (tx == NULL) {
-        SCLogDebug("tx is NULL, XFF cannot be retrieved");
-        return 0;
-    }
-
     htp_header_t *h_xff = NULL;
     if (tx->request_headers != NULL) {
         h_xff = htp_table_get_c(tx->request_headers, xff_cfg->header);
@@ -172,6 +146,38 @@ int HttpXFFGetIPFromTx(const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg,
     return 0;
 }
 
+/**
+ * \brief Function to return XFF IP if any in the selected transaction. The
+ * caller needs to lock the flow.
+ * \retval 1 if the IP has been found and returned in dstbuf
+ * \retval 0 if the IP has not being found or error
+ */
+int HttpXFFGetIPFromTx(
+        const Flow *f, uint64_t tx_id, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen)
+{
+    HtpState *htp_state = NULL;
+    uint64_t total_txs = 0;
+    htp_tx_t *tx = NULL;
+
+    htp_state = (HtpState *)FlowGetAppState(f);
+
+    if (htp_state == NULL) {
+        SCLogDebug("no http state, XFF IP cannot be retrieved");
+        return 0;
+    }
+
+    total_txs = AppLayerParserGetTxCnt(f, htp_state);
+    if (tx_id >= total_txs)
+        return 0;
+
+    tx = AppLayerParserGetTx(f->proto, ALPROTO_HTTP1, htp_state, tx_id);
+    if (tx == NULL) {
+        SCLogDebug("tx is NULL, XFF cannot be retrieved");
+        return 0;
+    }
+    return HttpXFFGetIPFromTxAux(f, tx, xff_cfg, dstbuf, dstbuflen);
+}
+
 /**
  *  \brief Function to return XFF IP if any. The caller needs to lock the flow.
  *  \retval 1 if the IP has been found and returned in dstbuf
@@ -190,9 +196,20 @@ int HttpXFFGetIP(const Flow *f, HttpXFFCfg *xff_cfg, char *dstbuf, int dstbuflen
     }
 
     total_txs = AppLayerParserGetTxCnt(f, htp_state);
-    for (; tx_id < total_txs; tx_id++) {
-        if (HttpXFFGetIPFromTx(f, tx_id, xff_cfg, dstbuf, dstbuflen) == 1)
+    AppLayerGetTxIteratorFunc IterFunc = AppLayerGetTxIterator(f->proto, f->alproto);
+    AppLayerGetTxIterState state;
+    memset(&state, 0, sizeof(state));
+
+    while (1) {
+        AppLayerGetTxIterTuple ires =
+                IterFunc(f->proto, f->alproto, f->alstate, tx_id, total_txs, &state);
+        if (ires.tx_ptr == NULL)
+            break;
+
+        if (HttpXFFGetIPFromTxAux(f, ires.tx_ptr, xff_cfg, dstbuf, dstbuflen) == 1)
             return 1;
+
+        tx_id = ires.tx_id + 1;
     }
 
 end: